package com.thiswhyme.storage.core.platform;

import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import com.thiswhyme.common.conststant.CommonConstant;
import com.thiswhyme.common.expection.BusinessException;
import com.thiswhyme.common.response.ResponseCode;
import com.thiswhyme.storage.core.FileStorage;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.function.Consumer;

/**
 * @description: 阿里云对象存储服务
 * @author: thiswhyme
 * @date: 2021/6/29
 */
@Slf4j
@AllArgsConstructor
public class AliyunOssStorage implements FileStorage {

    private String configKey;
    private String endpoint;
    private String accessKey;
    private String secretKey;
    private String bucketName;
    private String domain;

    private AliyunOssStorage() {

    }

    /**
     * 构建OSS
     * @return
     */
    public OSS getOss() {
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSupportCname(true);
        return new OSSClientBuilder().build(endpoint, accessKey, secretKey, conf);
    }

    /**
     * 关闭
     */
    public void shutdown(OSS oss) {
        if (oss != null) {
            oss.shutdown();
        }
    }

    @Override
    public String platformCode() {
        return PlatformType.OSS.name() + CommonConstant.HYPHEN + configKey;
    }

    @Override
    public String upload(InputStream inputStream, String keyName) {
        OSS oss = getOss();
        try {
            // 简单文件上传, 最大不能超过5GB
            PutObjectResult result = oss.putObject(bucketName, keyName, inputStream);
            log.info("文件上传成功，keyName：{}", keyName);
            return result.getETag();
        } catch (Exception ex) {
            log.error("文件上传失败，keyName：{}", keyName, ex);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件上传失败");
        } finally {
            shutdown(oss);
        }
    }

    @Override
    public void download(String keyName, Consumer<InputStream> consumer) {
        OSS oss = getOss();
        try {
            OSSObject ossObject = oss.getObject(bucketName, keyName);
            try (InputStream in = ossObject.getObjectContent()) {
                consumer.accept(in);
            } catch (Exception e) {
                log.error("文件下载失败，keyName：{}", keyName, e);
                throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件下载失败");
            }
        } catch (Exception e) {
            log.error("文件下载失败，keyName：{}", keyName, e);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件下载失败");
        } finally {
            shutdown(oss);
        }
    }

    @Override
    public String fetchDownloadUrl(String keyName, Long expire) {
        String result;
        OSS oss = getOss();
        try {
            if(null == expire) {
                result = domain + "/" + keyName;
            } else {
                GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, keyName);
                req.setExpiration(new Date(System.currentTimeMillis() + expire * 1000));
                URL url = oss.generatePresignedUrl(req);
                result = url.toString();
            }
        } catch (Exception ex) {
            log.error("获取文件下载路径失败，keyName：{}", keyName, ex);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "获取文件下载路径失败");
        } finally {
            shutdown(oss);
        }
        return result;
    }

    @Override
    public void batchDelete(List<String> keyNames) {
        if (CollectionUtils.isEmpty(keyNames)) {
            return;
        }

        OSS oss = getOss();
        try {
            DeleteObjectsResult result = oss.deleteObjects(new DeleteObjectsRequest(bucketName).withKeys(keyNames));
            log.info("文件批量删除成功，keyNames：{}, 结果：{}", keyNames, result.getDeletedObjects());
        } catch (Exception e) {
            log.error("文件批量删除失败，keyNames：{}", keyNames, e);
            throw new BusinessException(ResponseCode.SYSTEM_EXCEPTION.getCode(), "文件批量删除失败");
        } finally {
            shutdown(oss);
        }
    }
}
